﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Routing;

namespace Toolkit.Web.ExtensionMethods
{
    public static class DictionaryExtensions
    {
        /// <summary>
        /// Merges the specified instance.
        /// </summary>
        /// <param name="instance">The instance.</param>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <param name="replaceExisting">if set to <c>true</c> [replace existing].</param>
        public static void Merge(this IDictionary<string, object> instance, string key, object value, bool replaceExisting)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentException("key");
            }

            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            if (replaceExisting || !instance.ContainsKey(key))
            {
                instance[key] = value;
            }
        }

        /// <summary>
        /// Merges the specified instance.
        /// </summary>
        /// <param name="instance">The instance.</param>
        /// <param name="from">From.</param>
        /// <param name="replaceExisting">if set to <c>true</c> [replace existing].</param>
        public static void Merge(this IDictionary<string, object> instance, IDictionary<string, object> from, bool replaceExisting)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            if (from == null)
            {
                throw new ArgumentNullException("from");
            }

            foreach (KeyValuePair<string, object> pair in from)
            {
                if (!replaceExisting && instance.ContainsKey(pair.Key))
                {
                    continue; // Try the next
                }

                instance[pair.Key] = pair.Value;
            }
        }

        /// <summary>
        /// Merges the specified instance.
        /// </summary>
        /// <param name="instance">The instance.</param>
        /// <param name="from">From.</param>
        public static void Merge(this IDictionary<string, object> instance, IDictionary<string, object> from)
        {
            Merge(instance, from, true);
        }

        /// <summary>
        /// Merges the specified instance.
        /// </summary>
        /// <param name="instance">The instance.</param>
        /// <param name="values">The values.</param>
        /// <param name="replaceExisting">if set to <c>true</c> [replace existing].</param>
        public static void Merge(this IDictionary<string, object> instance, object values, bool replaceExisting)
        {
            Merge(instance, new RouteValueDictionary(values), replaceExisting);
        }

        /// <summary>
        /// Merges the specified instance.
        /// </summary>
        /// <param name="instance">The instance.</param>
        /// <param name="values">The values.</param>
        public static void Merge(this IDictionary<string, object> instance, object values)
        {
            Merge(instance, values, true);
        }

        /// <summary>
        /// Converts and optionally url encodes all key-value pairs to a url parameter string (querystring).
        /// Returns a string in the format {key1}={value1}&{key2}={value2}&...
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public static string ToUrlParameterString(this IDictionary<string, object> instance, bool encode)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            StringBuilder result = new StringBuilder();
            foreach (KeyValuePair<string, object> keyValuePair in instance)
            {
                if (encode)
                {
                    result.AppendFormat("{0}={1}&", HttpUtility.UrlEncode(keyValuePair.Key), HttpUtility.UrlEncode(keyValuePair.Value.ToString()));
                }
                else
                {
                    result.AppendFormat("{0}={1}&", keyValuePair.Key, keyValuePair.Value.ToString());
                }
            }
            return result.ToString();
        }

        /// <summary>
        /// Appends the in value.
        /// </summary>
        /// <param name="instance">The instance.</param>
        /// <param name="key">The key.</param>
        /// <param name="separator">The separator.</param>
        /// <param name="value">The value.</param>
        public static void AppendInValue(this IDictionary<string, object> instance, string key, string separator, object value)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentException("key");
            }

            if (string.IsNullOrEmpty(separator))
            {
                throw new ArgumentException("separator");
            }

            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            instance[key] = instance.ContainsKey(key) ? instance[key] + separator + value : value.ToString();
        }

        /// <summary>
        /// Appends the specified value at the beginning of the existing value
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="key"></param>
        /// <param name="separator"></param>
        /// <param name="value"></param>
        public static void PrependInValue(this IDictionary<string, object> instance, string key, string separator, object value)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance");
            }

            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentException("key");
            }

            if (string.IsNullOrEmpty(separator))
            {
                throw new ArgumentException("separator");
            }

            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            instance[key] = instance.ContainsKey(key) ? value + separator + instance[key] : value.ToString();
        }
    }
}
